package glassline;

import glassline.OvenAgent.glassState;
import glassline.interfaces.Conveyor;
import glassline.interfaces.Oven;
import glassline.interfaces.Shipper;
import glassline.interfaces.Shuttle;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import transducer.TChannel;
import transducer.TEvent;
import transducer.TReceiver;
import transducer.Transducer;
import agent.Agent;

public class ConveyorAgent extends Agent implements TReceiver, Conveyor{
	class MyGlass {
		Glass glass;
		GlassState state;
		GlassSource source;
		MyGlass(Glass g, GlassState glassStat, GlassSource source){
			glass = g;
			state = glassStat;
			this.source = source;
		}
	}
	class MyShipper{
		Shipper shipper;
		Boolean free;
		MyShipper(Shipper shipper){
			this.shipper = shipper;
			free = false;
		}
	}
	class MyOven{
		Oven oven;
		Boolean free;
		MyOven(Oven oven){
			this.oven = oven;
			free = true;
		}
		MyOven(Oven oven, Boolean bool){
			this.oven = oven;
			free = false;
		}
	}
	boolean exitSensor = false;
	boolean shipperSensor = false;
	public enum GlassState{waiting, moving};
	Timer timer = new Timer();
	public enum conveyorStatus{getSensor, moving, waiting, empty, gettingGlass, goingToOven, goingToShipper};
	public conveyorStatus conveyorStat;
	MyOven oven;
	MyShipper shipper;
	public enum GlassSource{shuttle, oven};
	public List<MyGlass>glassQueue = Collections.synchronizedList(new ArrayList<MyGlass>());
	public List<Boolean> sensors = Collections.synchronizedList(new ArrayList<Boolean>());
	Transducer transducer;
//	Shuttle shuttle = new Shuttle();
	private String name;
	
	public ConveyorAgent(String name, Transducer t){
		super();
		this.name = name;
		transducer = t;
		t.register(this, TChannel.SENSORS);
		t.register(this, TChannel.GUI);
		Boolean sensor1 = false;
		Boolean sensor2 = false;
		Boolean sensor3 = false;
		Boolean sensor4 = false;
		sensors.add(sensor1);
		sensors.add(sensor2);
		sensors.add(sensor3);
		sensors.add(sensor4);
//		conveyorStat = conveyorStatus.gettingGlass;
		print("initialized front conveyor");
	}
	
	public ConveyorAgent(String name, Transducer t, int back){
		super();
		this.name = name;
		transducer = t;
		t.register(this, TChannel.SENSORS);
		t.register(this, TChannel.GUI);
		Boolean sensor1 = false;
		sensors.add(sensor1);
//		conveyorStat = conveyorStatus.goingToShipper;
		print("initialized second conveyor");

	}
	
	public void msgHereIsGlass(Glass g){
		print("got a glass");
           	glassQueue.add(new MyGlass(g, GlassState.waiting, GlassSource.shuttle));
           	print("msgHereisGlass: " + glassQueue.size());
           	conveyorStat = conveyorStatus.goingToOven;
           	stateChanged();
	}
	
	public void msgHereIsGlassFromOven(Glass g){
		print("got a glass from oven");
       	glassQueue.add(new MyGlass(g, GlassState.waiting, GlassSource.oven));
       	print("msgHereisGlass: " + glassQueue.size());
       	conveyorStat = conveyorStatus.goingToShipper;
       	stateChanged();
	}
	
//message from oven for more glass
	public void msgIamDoneToOven() {
		print("got the message from the oven");
//		glassQueue.get(0).state = GlassState.goingToOven;
		conveyorStat = conveyorStatus.goingToOven;
		oven.free = true;
		stateChanged();
	}
	//message from shipper for more glass

	public void msgIamDoneToShipper(){
		print("got the message from the shipper");

//		glassQueue.get(0).state = GlassState.goingToShipper;
		shipper.free = true;
		conveyorStat = conveyorStatus.goingToShipper;
		stateChanged();
	}
	
	public boolean pickAndExecuteAnAction(){
		for(MyGlass m: glassQueue){
			if(m.source == GlassSource.shuttle && conveyorStat == conveyorStatus.goingToOven && oven.free == true){
				sendGlassToOven();
				return true;
			}
		}
		for(MyGlass m: glassQueue){
			if(m.source == GlassSource.oven && conveyorStat == conveyorStatus.goingToShipper && shipper.free == true){
				sendGlassToShipper();
				return true;
			}
		}

		if(conveyorStat == conveyorStatus.empty){
			askForGlass();
			return true;
		}
//		print("return false");
		return false;
	}
	
	void askForGlass(){
		print("asked shuttle to send a glass");
//		shuttle.msgIamDone();
		conveyorStat = conveyorStatus.waiting;
		stateChanged();
	}
	void sendGlassToOven(){
		print("sending the glass to oven");
		oven.oven.msgHereIsGlass(glassQueue.get(0).glass);
		conveyorStat = conveyorStatus.empty;
		oven.free = false;
		transducer.fireEvent(TChannel.GUI, TEvent.STARTCONVEYOR, null);
		timer.schedule(new TimerTask() {
			public void run(){//this routine is like a message reception    
//				glass.state = glassState.finishedBaking;
//				stateChanged();
			}
		}, 2000);

		transducer.fireEvent(TChannel.GUI, TEvent.STOPCONVEYOR, null);
		glassQueue.remove(0);
		stateChanged();
	}
	void sendGlassToShipper(){
		print("glassQueue To Shipper: "+ glassQueue.size());
		shipper.shipper.msgHereIsGlass(glassQueue.get(0).glass);
		oven.oven.msgIamDone();
		shipper.free = false;
		print("sending the glass to shipper");
		conveyorStat = conveyorStatus.empty;
		glassQueue.remove(0);
		stateChanged();
	}
	void getGlass(){
		//gui thing
//		transducer.fireEvent(TChannel.GUI, TEvent.STARTSHUTTLE, null);
//		stateChanged();
		print("getGlass");
//		return;
	}
	
	
	public void eventFired(TChannel channel, TEvent event, Object[]args){
		switch(event){
		case OVEN: 
			try{
				switch((Integer)args[0])
				{
				case 10: exitSensor = false;
						stateChanged();
					break;
				case 11: exitSensor = true;
						stateChanged();
					break;
				}
			}
			catch(Exception e){
				print(e.getMessage());
			}
		case SHIPPER:
			try{
				switch((Integer)args[0]){
				case 10: 
					shipperSensor = false;
					stateChanged();
					break;
				case 11:
					shipperSensor = true;
					stateChanged();
					break;
				}
			}catch(Exception e){
				print(e.getMessage());
			}
		case C1:
			try{
				switch((Integer)args[0]){
				case 10:
					for(Boolean b: sensors)
						b = false;
					stateChanged();
					break;
				case 11:
					sensors.set(0, true);
					stateChanged();
					break;
				case 21:
					sensors.set(1, true);
					stateChanged();
					break;
				case 31:
					sensors.set(2, true);
					stateChanged();
					break;
				case 41:
					sensors.set(3, true);
					stateChanged();
					break;
					
				}
			}catch(Exception e){
				print(e.getMessage());
			}
			break;
		}
	}
	public boolean getSensor(){
		for(Boolean b: sensors)
			if(b == true) return true;
		return false;
	}
	
	
	public void setShipper(Shipper s){
		this.shipper =  new MyShipper(s);
		msgIamDoneToShipper();

	}
	public void setOven(Oven o){
		this.oven = new MyOven(o);
		msgIamDoneToOven();
	}
	public void setOvenWithoutmessage(Oven o){
		this.oven = new MyOven(o, false);

	}
}